package com.project.web.api.gateway.config;

import com.google.common.util.concurrent.RateLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * zuul网关限流
 *
 * @author wyy
 * @date 2019-09-18 20:40
 */
//@Component todo 如果启用zuul网关打开注解
//public class RateLimitZuulFilter extends ZuulFilter {
public class RateLimitZuulFilter {
    /**
     * 日志工具类
     */
    public static final Logger log = LoggerFactory.getLogger(RateLimitZuulFilter.class);

    /**
     * 限流设置【每秒创建令牌数量】
     */
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

    /**
     * 注入redis工具类
     */
//    @Autowired
//    private RedisClient redisClient;

    /**
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
//    @Override
//    public String filterType() {
//        return PRE_TYPE;
//    }

    /**
     * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
     * important for a filter. filterOrders do not need to be sequential.
     *
     * @return the int order of a filter
     */
//    @Override
//    public int filterOrder() {
//        return SERVLET_DETECTION_FILTER_ORDER - 1;
//    }

    /**
     * a "true" return from this method means that the run() method should be invoked
     *
     * @return true if the run() method should be invoked. false will not invoke the run() method
     */
//    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * if shouldFilter() is true, this method will be invoked. this method is the app method of a ZuulFilter
     *
     * @return Some arbitrary artifact may be returned. Current implementation ignores it.
     */
//    @Override
    public Object run() {
/*
        // 获取请求头参数
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String apiToken = request.getParameter("apiToken");
        String apiId = request.getParameter("apiId");

        // 判断限流
        if (!RATE_LIMITER.tryAcquire()) {
            log.error("API网管限流已触发");
            Result<String> result = new Result<>();
            result.setResult("success");
            result.setErrorCode("1001");
            result.setErrorMsg("API GATEWAY RATE_LIMITER");
            try {
                String jsonStr = JacksonUtil.toJsonStr(result);
                currentContext.setSendZuulResponse(false);
                currentContext.setResponseBody(jsonStr);
                currentContext.setResponseStatusCode(500);
            } catch (IOException e) {
                log.error("API 网关限速JSON转化出错");
            }
        }

        // 判断请求头参数
        Object redisApiToken = redisClient.get(RedisConsts.API_TOKEN_KEY + apiId);
        if (StringUtils.isBlank(apiToken) || StringUtils.isBlank(apiId)
                || redisApiToken == null || !StringUtils.equals(redisApiToken.toString(), apiToken)) {

            //返回错误提示
            Result<String> result = new Result<>();
            result.setResult("success");
            result.setErrorCode("1007");
            result.setErrorMsg("缺少必须的参数");
            try {
                String jsonStr = JacksonUtil.toJsonStr(result);
                currentContext.setResponseBody(jsonStr);
                currentContext.setSendZuulResponse(false);
                currentContext.setResponseStatusCode(500);
            } catch (IOException e) {
                log.error("API 网关限速JSON转化出错");
            }

            return null;
        } else {
            // 如果apiToken 令牌验证通过，则重置生效时间
            redisClient.setAndExpire(RedisConsts.API_TOKEN_KEY + apiId, apiToken, RedisConsts.API_TOKEN_EXPIRE);
        }*/
        return null;
    }
}
